#include "broadway-output.h"
+#define _XOPEN_SOURCE /* for crypt */
+
#include <glib.h>
#include <glib/gprintf.h>
#include "gdktypes.h"
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <crypt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
struct _BroadwayServer {
GObject parent_instance;
+ char *password;
char *address;
int port;
GSocketService *service;
struct BroadwayInput {
BroadwayServer *server;
+ BroadwayOutput *output;
GSocketConnection *connection;
GByteArray *buffer;
GSource *source;
gint64 time_base;
gboolean proto_v7_plus;
gboolean binary;
+ gboolean active;
};
struct BroadwayWindow {
broadway_server_init (BroadwayServer *server)
{
BroadwayWindow *root;
+ char *passwd_file;
+ char *password, *p;
server->service = g_socket_service_new ();
server->pointer_grab_window_id = -1;
server->id_ht = g_hash_table_new (NULL, NULL);
server->id_counter = 0;
+ passwd_file = g_build_filename (g_get_user_config_dir (),
+ "broadway.passwd", NULL);
+
+ if (g_file_get_contents (passwd_file,
+ &password, NULL, NULL))
+ {
+ p = strchr (password, '\n');
+ if (p)
+ *p = 0;
+ g_strstrip (password);
+ if (strlen (password) > 3)
+ server->password = password;
+ else
+ g_free (password);
+ }
+
root = g_new0 (BroadwayWindow, 1);
root->id = server->id_counter++;
root->width = 1024;
object_class->finalize = broadway_server_finalize;
}
-static void start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary);
+static void start (BroadwayInput *input);
static void
http_request_free (HttpRequest *request)
server->future_mouse_in_toplevel = data->mouse_window_id;
}
+static gboolean
+verify_password (BroadwayServer *server, const char *password)
+{
+ char *hash;
+ hash = crypt (password, server->password);
+ return strcmp (hash, server->password) == 0;
+}
+
static void
parse_input_message (BroadwayInput *input, const char *message)
{
char *p;
gint64 time_;
+ if (!input->active)
+ {
+ /* The input has not been activated yet, handle auth/start */
+
+ if (message[0] != 'l' ||
+ !verify_password (server, message+1))
+ {
+ broadway_output_request_auth (input->output);
+ broadway_output_flush (input->output);
+ }
+ else
+ start (input);
+
+ return;
+ }
+
memset (&msg, 0, sizeof (msg));
p = (char *)message;
}
break;
case BROADWAY_WS_CNX_PING:
- broadway_output_pong (server->output);
+ broadway_output_pong (input->output);
break;
case BROADWAY_WS_CNX_PONG:
break; /* we never send pings, but tolerate pongs */
if (buf[0] != 0)
{
- server->input = NULL;
+ if (server->input == input)
+ server->input = NULL;
broadway_input_free (input);
return;
}
if (len > 0 && buf[0] != 0)
{
- server->input = NULL;
+ if (server->input == input)
+ server->input = NULL;
broadway_input_free (input);
break;
}
}
static void
-broadway_server_read_all_input_nonblocking (BroadwayServer *server)
+broadway_server_read_all_input_nonblocking (BroadwayInput *input)
{
GInputStream *in;
gssize res;
guint8 buffer[1024];
GError *error;
- BroadwayInput *input;
- if (server->input == NULL)
+ if (input == NULL)
return;
- input = server->input;
-
in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
error = NULL;
return;
}
- server->input = NULL;
+ if (input->server->input == input)
+ input->server->input = NULL;
broadway_input_free (input);
if (res < 0)
{
static void
broadway_server_consume_all_input (BroadwayServer *server)
{
- broadway_server_read_all_input_nonblocking (server);
+ broadway_server_read_all_input_nonblocking (server->input);
/* Since we're parsing input but not processing the resulting messages
we might not get a readable callback on the stream, so queue an idle to
{
BroadwayServer *server = input->server;
- broadway_server_read_all_input_nonblocking (server);
+ broadway_server_read_all_input_nonblocking (input);
- process_input_messages (server);
+ if (input->active)
+ process_input_messages (server);
return TRUE;
}
gsize len;
GChecksum *checksum;
char *origin, *host;
- BroadwayServer *server;
BroadwayInput *input;
const void *data_buffer;
gsize data_buffer_size;
GInputStream *in;
char *key_v7;
gboolean proto_v7_plus;
-
- server = request->server;
+ GSocket *socket;
+ int flag = 1;
#ifdef DEBUG_WEBSOCKETS
g_print ("incoming request:\n%s\n", request->request->str);
proto_v7_plus = FALSE;
}
-
- if (server->input != NULL)
- {
- broadway_input_free (server->input);
- server->input = NULL;
- }
+ socket = g_socket_connection_get_socket (request->connection);
+ setsockopt (g_socket_get_fd (socket), IPPROTO_TCP,
+ TCP_NODELAY, (char *) &flag, sizeof(int));
input = g_new0 (BroadwayInput, 1);
-
input->server = request->server;
input->connection = g_object_ref (request->connection);
input->proto_v7_plus = proto_v7_plus;
input->buffer = g_byte_array_sized_new (data_buffer_size);
g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
- server->input = input;
-
- start_output (request, proto_v7_plus, binary);
+ input->output =
+ broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+ 0, proto_v7_plus, binary);
/* This will free and close the data input stream, but we got all the buffered content already */
http_request_free (request);
g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL);
g_source_attach (input->source, NULL);
+ if (input->server->password)
+ {
+ broadway_output_request_auth (input->output);
+ broadway_output_flush (input->output);
+ }
+ else
+ start (input);
+
/* Process any data in the pipe already */
parse_input (input);
- process_input_messages (server);
g_strfreev (lines);
}
static void
-start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary)
+start (BroadwayInput *input)
{
- GSocket *socket;
BroadwayServer *server;
- int flag = 1;
- socket = g_socket_connection_get_socket (request->connection);
- setsockopt(g_socket_get_fd (socket), IPPROTO_TCP,
- TCP_NODELAY, (char *) &flag, sizeof(int));
+ input->active = TRUE;
+
+ server = BROADWAY_SERVER (input->server);
+
+ if (server->output)
+ {
+ broadway_output_disconnected (server->output);
+ broadway_output_flush (server->output);
+ }
+
+ if (server->input != NULL)
+ {
+ broadway_input_free (server->input);
+ server->input = NULL;
+ }
- server = BROADWAY_SERVER (request->server);
+ server->input = input;
if (server->output)
{
server->saved_serial = broadway_output_get_next_serial (server->output);
broadway_output_free (server->output);
}
+ server->output = input->output;
- server->output =
- broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
- server->saved_serial, proto_v7_plus, binary);
+ broadway_output_set_next_serial (server->output, server->saved_serial);
+ broadway_output_auth_ok (server->output);
+ broadway_output_flush (server->output);
broadway_server_resync_windows (server);
broadway_output_grab_pointer (server->output,
server->pointer_grab_window_id,
server->pointer_grab_owner_events);
+
+ process_input_messages (server);
}
static void
var command = cmd.get_char();
lastSerial = cmd.get_32();
switch (command) {
+ case 'l':
+ login ();
+ break;
+
+ case 'L':
+ if (loginDiv != null)
+ loginDiv.parentNode.removeChild(loginDiv);
+ start ();
+ break;
+
+ case 'D':
+ alert ("disconnected");
+ inputSocket = null;
+ break;
+
case 's': // create new surface
id = cmd.get_16();
x = cmd.get_16s();
return ws;
}
+function start()
+{
+ setupDocument(document);
+
+ var w, h;
+ w = window.innerWidth;
+ h = window.innerHeight;
+ window.onresize = function(ev) {
+ var w, h;
+ w = window.innerWidth;
+ h = window.innerHeight;
+ sendInput ("d", [w, h]);
+ };
+ sendInput ("d", [w, h]);
+}
+
+var loginDiv = null;
+function login()
+{
+ if (loginDiv == null) {
+ var div = document.createElement('div');
+ document.body.appendChild(div);
+ div.innerHTML = "Please enter password<br>";
+ div.style.marginTop = "40px";
+ div.style.textAlign = "center";
+
+ var input = document.createElement("input");
+ input.setAttribute("type", "password");
+ div.appendChild(input);
+ input.onkeyup = function(e) {
+ if (e.keyCode === 13) {
+ inputSocket.send ("l" + input.value);
+ }
+ }
+ input.focus ();
+ loginDiv = div;
+ } else {
+ alert ("Wrong password");
+ }
+}
+
function connect()
{
var url = window.location.toString();
ws.onopen = function() {
inputSocket = ws;
- var w, h;
- w = window.innerWidth;
- h = window.innerHeight;
- window.onresize = function(ev) {
- var w, h;
- w = window.innerWidth;
- h = window.innerHeight;
- sendInput ("d", [w, h]);
- };
- sendInput ("d", [w, h]);
};
ws.onclose = function() {
+ if (inputSocket != null)
+ alert ("disconnected");
inputSocket = null;
};
ws.onmessage = function(event) {
handleMessage(event.data);
};
-
- setupDocument(document);
}